package preprocess;

import ptolemy.kernel.*;
import ptolemy.kernel.util.*;

import java.util.*;

import ptolemy.domains.sdf.kernel.*;
import ptolemy.domains.de.kernel.*;
import ptolemy.domains.pn.kernel.*;
import ptolemy.domains.csp.kernel.*;
import ptolemy.domains.sr.kernel.*;
import ptolemy.domains.ct.kernel.*;

import db.*;
import gui.*;
import MoC.*;
import util.Util;
import FlowGraph.*;
import FlowGraph.Nodes.MethodCallNode;

//////////////////////////////////////////////////////////////////////////
//// Preprocess
/**
        Contem a lista de atores e os resultados da etapa de preprocess.

@author Ivan Jeukens
@version v 0.1 08/10/2002
*/
public class Preprocess {

    public Preprocess() {
        _result = new ResultMessages("Preprocess");
    }

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    public void performChecks(Iterator actors, Iterator classes) {

        HashMap map = new HashMap();
        while(actors.hasNext()) {
            // Detecta se eh SR Specific
            AtomicActorInfo ainfo = (AtomicActorInfo) actors.next();
            ComponentEntity ce = ainfo.getActor();

            if(map.containsKey(ainfo.getClassInfo())) continue;
            map.put(ainfo.getClassInfo(), null);

            Attribute at = ce.getAttribute("_nonStrictMarker");
            if(at != null) {
                _processAttribute(ainfo, "SR", ce);
            }
        }

        while(classes.hasNext()) {
            ClassInfo cinfo = (ClassInfo) classes.next();

            LinkedList l = _createInfoCollectors();

            boolean CTSpecific = false;
            Iterator ite = cinfo.classesIterator();
            while(ite.hasNext()) {
                ClassData cdata = (ClassData) ite.next();
                cdata.visit(l);

                // Verifica se eh CT Specific
                if(!CTSpecific) {
                    Iterator imp = cdata.implementsIterator();
                    while(imp.hasNext()) {
                        String name = (String) imp.next();
                        if(_isCTInterface(name)) {
                            CTSpecific = true;
                        }
                    }
                }
            }

            boolean isDEActor = false;
            boolean isCSPActor = false;

            Class c = cinfo.getActorClass();
            if(Util.isSubClass(c,
                    ptolemy.domains.de.kernel.DEActor.class)) {
                isDEActor = true;
            }
            else
            if(Util.isSubClass(c,
                    ptolemy.domains.csp.kernel.CSPActor.class)) {
                isCSPActor = true;
            }

            _buildResult(cinfo, l, CTSpecific, isDEActor, isCSPActor);
        }
    }

    public ResultMessages getResult() {
        return _result;
    }

    ///////////////////////////////////////////////////////////////////
    ////                         private methods                   ////

    private void _processAttribute(AtomicActorInfo ainfo, String MOC, Entity ce) {
        ClassResult res = ainfo.getResult();
        if(res.isSpecific()) {
            Message m = _newMessage(ainfo.getName(), Message.NOMOC,
                Message.ERROR, Message.MULTIMOC_SPECIFIC ,
                new String("Actor " + ce.getFullName() +
                    " was detected specific for at least " +
                    MOC + " and " + res.getSpecificMoC()));
            ActorMessageLocation er = new ActorMessageLocation(
                MessageLocation.ACTOR);
            ClassInfo cinfo = ainfo.getClassInfo();
            er.setUsedByActors(cinfo.getUsedBy());
            m.setLocation(er);
            res.setHasError(true);
            return;
        }
        else {
            res.setSpecificMoC(MOC);
        }
    }
    
    private LinkedList _createInfoCollectors() {
        LinkedList ret = new LinkedList();

        CommonInfoCollector common = new CommonInfoCollector();
        ret.add(common);

        SDFInfoCollector sdfcol = new SDFInfoCollector();
        ret.add(sdfcol);
        
        DEInfoCollector decol = new DEInfoCollector();
        ret.add(decol);

        CSPInfoCollector cspcol = new CSPInfoCollector();
        ret.add(cspcol);

        return ret;
    }

    private boolean _isCTInterface(String name) {
        if(name.equals("CTDynamicActor") ||
           name.equals("ptolemy.domains.ct.kernel.CTDynamicActor") ||
           name.equals("CTEventGenerator") ||
           name.equals("ptolemy.domains.ct.kernel.CTEventGenerator") ||
           name.equals("CTStatefulActor") ||
           name.equals("ptolemy.domains.ct.kernel.CTStatefulActor") ||
           name.equals("CTStepSizeControlActor") ||
           name.equals("ptolemy.domains.ct.kernel.CTStepSizeControlActor") ||
           name.equals("CTWaveformGenerator") ||
           name.equals("ptolemy.domains.ct.kernel.CTWaveformGenerator")) {
            return true;
        }
        return false;
    }

    // Quando chamo esse metodo, ja sei se eh SR Specific ou nao
    private void _buildResult(ClassInfo cinfo, LinkedList l,
            boolean CTSpecific, boolean isDEActor, boolean isCSPActor) {

        ClassResult cres = cinfo.getResult();
        String specificMoC = null;

        CommonInfoCollector col = (CommonInfoCollector) l.get(0);
        specificMoC = _processCommonInfoCollector(cinfo, col);
        if(specificMoC != null && specificMoC.equals("Error")) {
            cres.setHasError(true);
            return;
        }

        SDFInfoCollector sdfcol = (SDFInfoCollector) l.get(1);
        specificMoC = _processSDFSpecific(cinfo, specificMoC,
            sdfcol);
        if(specificMoC != null && specificMoC.equals("Error")) {
            cres.setHasError(true);
            return;
        }

        DEInfoCollector decol = (DEInfoCollector) l.get(2);
        specificMoC = _processDESpecific(cinfo, specificMoC,
            isDEActor, decol);
        if(specificMoC != null && specificMoC.equals("Error")) {
            cres.setHasError(true);
            return;
        }

        CSPInfoCollector cspcol = (CSPInfoCollector) l.get(3);
        specificMoC = _processCSPSpecific(cinfo, specificMoC,
            isCSPActor, cspcol);
        if(specificMoC != null && specificMoC.equals("Error")) {
            cres.setHasError(true);
            return;
        }

        if(cres.isSpecific() && specificMoC != null) {
            if(cres.getSpecificMoC().equals(specificMoC)) {
                Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                    Message.INFORMATION, Message.SPECIFIC_ACTOR,
                    new String("Actor " + cinfo.getName() +
                    " indentified as " + specificMoC + " specific."));
                ActorMessageLocation er = new ActorMessageLocation(
                    ActorMessageLocation.ACTOR);
                er.setUsedByActors(cinfo.getUsedBy());
                m.setLocation(er);
            }
            else {
                Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                    Message.ERROR, Message.MULTIMOC_SPECIFIC ,
                    new String("Actor " + cinfo.getName() +
                        "was detected specific for at least " +
                        specificMoC + " and " + cres.getSpecificMoC()));
                ActorMessageLocation er = new ActorMessageLocation(
                    MessageLocation.ACTOR);
                er.setUsedByActors(cinfo.getUsedBy());
                m.setLocation(er);
                cres.setHasError(true);
                return;
            }
        }
        else
        if(cres.isSpecific() && specificMoC == null) {
            Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                    Message.INFORMATION, Message.SPECIFIC_ACTOR,
                    new String("Actor " + cinfo.getName() +
                    " indentified as " + cres.getSpecificMoC() + " specific."));
            ActorMessageLocation er = new ActorMessageLocation(
                ActorMessageLocation.ACTOR);
            er.setUsedByActors(cinfo.getUsedBy());
            m.setLocation(er);
        }
        else {
            if(specificMoC != null) {
                cres.setSpecificMoC(specificMoC);
                Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                    Message.INFORMATION, Message.SPECIFIC_ACTOR,
                    new String("Actor " + cinfo.getName() +
                    " indentified as " + specificMoC + " specific."));
                ActorMessageLocation er = new ActorMessageLocation(
                    ActorMessageLocation.ACTOR);
                er.setUsedByActors(cinfo.getUsedBy());
                m.setLocation(er);
            }
            else {
                Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                    Message.INFORMATION, Message.GENERIC_ACTOR,
                    new String("Actor " + cinfo.getName() +
                    " indentified as generic."));
                ActorMessageLocation er = new ActorMessageLocation(
                    ActorMessageLocation.ACTOR);
                er.setUsedByActors(cinfo.getUsedBy());
                m.setLocation(er);
            }
        }

        // Neste ponto, eu ja sei se o ator atomico eh especifico para um
        // dado modelo computacional, ou se ele tem metodos temporais.
        if(cres.isTimed()) {
            if(!cres.isSpecific()) {
                cres.setValidFor("CSP");
                cres.setValidFor("PN");
            }
            else {
                String name = cres.getSpecificMoC();
                if(name.equals("CSP")) {
                    cres.setValidFor("CSP");
                }
                else
                if(name.equals("DE")) {
                    cres.setValidFor("DE");
                }
                else
                if(name.equals("CT")) {
                    cres.setValidFor("CT");
                }
            }
        }
        else {
            if(!cres.isSpecific()) {
                cres.addToVerify("SDF");
                cres.addToVerify("SR");
                cres.setValidFor("CSP");
                cres.setValidFor("PN");
            }
            else {
                String name = cres.getSpecificMoC();
                if(name.equals("SR")) {
                    cres.addToVerify("SR");
                }
                else
                if(name.equals("SDF")) {
                    cres.addToVerify("SDF");
                }
                else
                if(name.equals("CSP")) {
                    cres.setValidFor("CSP");
                }
            }
        } 
    }

    private String _processCSPSpecific(ClassInfo info, String specificMoC,
            boolean isCSPActor, CSPInfoCollector cspcol) {
        String actorname = info.getName();
        boolean hasCSPMethod = false;

        if(cspcol.cspMethodSize() > 0) {
            hasCSPMethod = true;
        }

        if(isCSPActor) {
            if(specificMoC != null && !specificMoC.equals("CSP")) {
                Message m = _newMessage(info.getName(), Message.CSP,
                        Message.ERROR, Message.CSPACTOR_NOTCSPSPECIFIC,
                        new String("Actor " + info.getName() + " extends CSPActor " +
                        " but was detected as " + specificMoC + " specific."));
                ActorMessageLocation er = new ActorMessageLocation(
                    MessageLocation.ACTOR);
                er.setUsedByActors(info.getUsedBy());
                m.setLocation(er);
                return "Error";
            }
            else
            if(hasCSPMethod) {
                Message m = _newMessage(info.getName(), Message.CSP,
                        Message.INFORMATION, Message.HASCSPMETHODS,
                        new String("Actor " + info.getName() + " has" +
                        " CSP specific methods."));
                ClassMessageLocation er = new ClassMessageLocation(
                    MessageLocation.CLASS_SOURCE);
                er.setClassInfo(info);

                Iterator ite = cspcol.methodIterator();
                while(ite.hasNext()) {
                    MethodCallNode mc = (MethodCallNode) ite.next();
                    er.addLine(mc.getLine());
                }
                m.setLocation(er);

                specificMoC = "CSP";
            }
            else {
                // Como no de. O cara pode tar usando a classe
                // director com os metodos de tempo. Ai ta certo
                // Senao e desnecessario o CSPActor.

                if(specificMoC == null) {

                }
                else {

                }

                specificMoC = "CSP";
            }
        }
        else {
            if(hasCSPMethod) {
                if(specificMoC == null) {
                    Message m = _newMessage(info.getName(), Message.CSP,
                            Message.INFORMATION, Message.HASCSPMETHODS,
                            new String("Actor " + info.getName() + " has" +
                            " CSP specific methods."));
                    ClassMessageLocation er = new ClassMessageLocation(
                        ClassMessageLocation.CLASS_SOURCE);
                    er.setClassInfo(info);

                    Iterator ite = cspcol.methodIterator();
                    while(ite.hasNext()) {
                        MethodCallNode mc = (MethodCallNode) ite.next();
                        er.addLine(mc.getLine());
                    }
                    m.setLocation(er);

                    specificMoC = "CSP";
                }
                else 
                if(specificMoC.equals("CSP")) {

                }
                else {
                    Message m = _newMessage(info.getName(), Message.CSP,
                        Message.ERROR, Message.CSPACTOR_NOTCSPSPECIFIC,
                        new String("Actor " + info.getName() + " contains CSP " +
                        " methods but was detected as " + specificMoC + " specific."));
                    ActorMessageLocation er = new ActorMessageLocation(
                        MessageLocation.ACTOR);
                    er.setUsedByActors(info.getUsedBy());
                    m.setLocation(er);

                    return "Error";
                }
            }
        }
        return specificMoC;
    }
    
    private String _processDESpecific(ClassInfo cinfo,
            String specificMoC, boolean isDEActor,
            DEInfoCollector decol) {
        String actorname = cinfo.getName();
        boolean hasDEPort = false;
        boolean hasDEMethod = false;

        if(decol.dePortsSize() > 0) {
            hasDEPort = true;
        }
        if(decol.deMethodSize() > 0) {
            hasDEMethod = true;
        }

        if(isDEActor) {
            if(specificMoC != null && !specificMoC.equals("DE")) {
                Message m = _newMessage(cinfo.getName(), Message.DE,
                        Message.ERROR, Message.DEACTOR_NOTDESPECIFIC,
                        new String("Actor " + cinfo.getName() + " extends DEActor " +
                        " but was detected as " + specificMoC + " specific."));
                ActorMessageLocation er = new ActorMessageLocation(
                   MessageLocation.ACTOR);
                er.setUsedByActors(cinfo.getUsedBy());
                m.setLocation(er);
                return "Error";
            }
            else
            if(!hasDEPort) {
                // So se estiver usando o Director com comandos de 
                // tempo. Tenho que criar um metodo para verificar isso.
                if(specificMoC == null) {

                }
                else {

                }
                specificMoC = "DE";
            }
            else
            if(hasDEPort && !hasDEMethod) {
                Message m = _newMessage(cinfo.getName(), Message.DE,
                        Message.INFORMATION, Message.HASDEIOPORTS,
                        new String("Actor " + cinfo.getName() + " has" +
                        " DEIOPorts."));
                ActorMessageLocation er = new ActorMessageLocation(
                    MessageLocation.ACTOR);
                er.setUsedByActors(cinfo.getUsedBy());
                m.setLocation(er);

                specificMoC = "DE";
            }
            else {
                // tem porto e metodo DE
                Message m = _newMessage(cinfo.getName(), Message.DE,
                        Message.INFORMATION, Message.HASDEMETHODS,
                        new String("Actor " + cinfo.getName() + " has" +
                        " DE specific methods."));
                ClassMessageLocation er = new ClassMessageLocation(
                    MessageLocation.CLASS_SOURCE);
                er.setClassInfo(cinfo);

                Iterator ite = decol.deMethodIterator();
                while(ite.hasNext()) {
                    MethodCallNode mc = (MethodCallNode) ite.next();
                    er.addLine(mc.getLine());
                }
                m.setLocation(er);

                specificMoC = "DE";
            } 
        }
        else {
            if(hasDEPort && !hasDEMethod) {
                if(specificMoC != null && !specificMoC.equals("DE")) {
                    Message m = _newMessage(cinfo.getName(), Message.DE,
                        Message.ERROR, Message.DEACTOR_NOTDESPECIFIC,
                        new String("Actor " + cinfo.getName() + " has DEIOPorts" +
                        " but was detected as " + specificMoC + " specific."));
                    ActorMessageLocation er = new ActorMessageLocation(
                        MessageLocation.ACTOR);
                    er.setUsedByActors(cinfo.getUsedBy());
                    m.setLocation(er);
                    return "Error";
                }
                else
                if(specificMoC == null) {
                    // mesma coisa que o outro caso. O cara deve estar
                    // usando o getdirector.
                }
                else {
                   Message m = _newMessage(cinfo.getName(), Message.DE,
                        Message.INFORMATION, Message.HASDEIOPORTS,
                        new String("Actor " + cinfo.getName() + " has" +
                        " DEIOPorts."));
                    ActorMessageLocation er = new ActorMessageLocation(
                        MessageLocation.ACTOR);
                    er.setUsedByActors(cinfo.getUsedBy());
                    m.setLocation(er);
                    specificMoC = "DE";
                }
            }
            else
            if(hasDEPort && hasDEMethod) {
                if(specificMoC != null && !specificMoC.equals("DE")) {
                    Message m = _newMessage(cinfo.getName(), Message.DE,
                        Message.ERROR, Message.DEACTOR_NOTDESPECIFIC,
                        new String("Actor " + cinfo.getName() + " has DEIOPorts" +
                        " and uses DE specific methods but was detected " +
                        " as " + specificMoC + " specific."));
                    ActorMessageLocation er = new ActorMessageLocation(
                        ActorMessageLocation.ACTOR);
                    er.setUsedByActors(cinfo.getUsedBy());
                    m.setLocation(er);
                    return "Error";
                }
                else {
                    Message m = _newMessage(cinfo.getName(), Message.DE,
                            Message.INFORMATION, Message.HASDEMETHODS,
                            new String("Actor " + cinfo.getName() + " has" +
                            " DE specific methods."));
                    ClassMessageLocation er = new ClassMessageLocation(
                        MessageLocation.CLASS_SOURCE);
                    er.setClassInfo(cinfo);

                    Iterator ite = decol.deMethodIterator();
                    while(ite.hasNext()) {
                        MethodCallNode mc = (MethodCallNode) ite.next();
                        er.addLine(mc.getLine());
                    }
                    m.setLocation(er);

                    specificMoC = "DE";
                }
            }
        }

        return specificMoC;
    }

    private String _processSDFSpecific(ClassInfo info, String specificMoC,
            SDFInfoCollector sdfcol) {
        String actorname = info.getName();
        boolean hasSDFPort = false;
        boolean hasSDFMethod = false;

        if(sdfcol.sdfPortsSize() > 0) {
            hasSDFPort = true;
        }
        if(sdfcol.sdfMethodSize() > 0) {
            hasSDFMethod = true;
        }

        if(specificMoC != null) {
            if(specificMoC.equals("SDF")) {
                if(hasSDFPort && !hasSDFMethod) {
                    Message m = _newMessage(actorname, Message.SDF,
                        Message.WARNING, Message.SDFPORT_NOSDFMETHOD,
                        new String("Actor " + actorname + " specific to SDF," +
                        " contains SDF ports but no SDF specific method."));
                    ActorMessageLocation er = new ActorMessageLocation(
                        ActorMessageLocation.ACTOR);
                    er.setUsedByActors(info.getUsedBy());
                    m.setLocation(er);
                }
                else {
                    // continua na mesma
                }
            }
            else {
                if(hasSDFPort && !hasSDFMethod) {
                    Message m = _newMessage(actorname, Message.SDF,
                        Message.ERROR, Message.SDFPORT_NOTSDFSPECIFIC,
                        new String("Actor " + actorname + " specific to " +
                        specificMoC + " but contains SDF ports."));
                    ActorMessageLocation er = new ActorMessageLocation(
                        ActorMessageLocation.ACTOR);
                    er.setUsedByActors(info.getUsedBy());
                    m.setLocation(er);
                    return "Error";
                }
                else
                if(hasSDFMethod) {
                    Message m = _newMessage(actorname, Message.SDF,
                        Message.ERROR, Message.SDFMETHOD_NOTSDFSPECIFIC,
                        new String("Actor " + actorname + " specific to " +
                        specificMoC + " but contains SDF methods."));
                    ClassMessageLocation er = new ClassMessageLocation(
                        ClassMessageLocation.CLASS_SOURCE);
                    er.setClassInfo(info);
                    Iterator ite = sdfcol.sdfMethodIterator();
                    while(ite.hasNext()) {
                        MethodCallNode mc = (MethodCallNode) ite.next();
                        er.addLine(mc.getLine());
                    }
                    m.setLocation(er);
                    return "Error";
                }
            }
        }
        else {
            if(hasSDFPort && !hasSDFMethod) {
                // nao considero SDF
                Message m = _newMessage(info.getName(), Message.SDF,
                        Message.WARNING, Message.SDFPORT_NOTSDFSPECIFIC,
                        new String("Actor contains SDF ports but no SDF " +
                        " methods. Not classified as SDF specific."));
                ActorMessageLocation er = new ActorMessageLocation(
                    ActorMessageLocation.ACTOR);
                er.setUsedByActors(info.getUsedBy());
                m.setLocation(er);
            }
            else
            if(hasSDFMethod) {
                Message m = _newMessage(actorname, Message.SDF,
                        Message.INFORMATION, Message.SDFSPECIFIC,
                        new String("Actor " + actorname + " detected as "  +
                        " SDF specific."));
                ClassMessageLocation er = new ClassMessageLocation(
                    ClassMessageLocation.CLASS_SOURCE);
                er.setClassInfo(info);
                Iterator ite = sdfcol.sdfMethodIterator();
                while(ite.hasNext()) {
                    MethodCallNode mc = (MethodCallNode) ite.next();
                    er.addLine(mc.getLine());
                }
                m.setLocation(er);
                specificMoC = "SDF";
            }
        }
        return specificMoC;
    }
    
    private String _processCommonInfoCollector(ClassInfo cinfo,
            CommonInfoCollector col) {

        LinkedList nodes = new LinkedList();
        MethodCallNode previous = null;
        String mocname = null;

        // Determina a presanca de cast para um diretor especifico

        Iterator ite = col.nodeIterator();
        while(ite.hasNext()) {
            MethodCallNode mc = (MethodCallNode) ite.next();
            // Se o return for Director, entao nao faz nada.
            Class type = mc.getReturnType();
            if(Util.isSubClass(type, SDFDirector.class)) {
                if(mocname != null && !mocname.equals("SDF")) {
                    _distinctMoCMessage(cinfo, mc, previous);
                    return "Error";
                }
                else {
                    mocname = "SDF";
                    previous = mc;
                    nodes.add(mc);
                }
            }
            else
            if(Util.isSubClass(type, DEDirector.class)) {
                if(mocname != null && !mocname.equals("DE")) {
                    _distinctMoCMessage(cinfo, mc, previous);
                    return "Error";
                }
                else {
                    mocname = "DE";
                    previous = mc;
                    nodes.add(mc);
                }
            }
            else
            if(Util.isSubClass(type, SRDirector.class)) {
                if(mocname != null && !mocname.equals("SR")) {
                    _distinctMoCMessage(cinfo, mc, previous);
                    return "Error";
                }
                else {
                    mocname = "SR";
                    previous = mc;
                    nodes.add(mc);
                }
            }
            else
            if(Util.isSubClass(type, PNDirector.class)) {
                if(mocname != null && !mocname.equals("PN")) {
                    _distinctMoCMessage(cinfo, mc, previous);
                    return "Error";
                }
                else {
                    mocname = "PN";
                    previous = mc;
                    nodes.add(mc);
                }
            }
            else
            if(Util.isSubClass(type, CSPDirector.class)) {
                if(mocname != null && !mocname.equals("CSP")) {
                    _distinctMoCMessage(cinfo, mc, previous);
                    return "Error";
                }
                else {
                    mocname = "CSP";
                    previous = mc;
                    nodes.add(mc);
                }
            }
            else
            if(Util.isSubClass(type, CTDirector.class)) {
                if(mocname != null && !mocname.equals("CT")) {
                    _distinctMoCMessage(cinfo, mc, previous);
                    return "Error";
                }
                else {
                    mocname = "CT";
                    previous = mc;
                    nodes.add(mc);
                }
            }
        }

        if(col.isTimed()) {
            ClassResult res = cinfo.getResult();
            res.setUseTime();

            Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                Message.INFORMATION, Message.ISTIMED,
                "Actor " + cinfo.getName() + " is timed");
            ClassMessageLocation er = new ClassMessageLocation(
                MessageLocation.CLASS_SOURCE);
            er.setClassInfo(cinfo);
            Iterator nite = col.timedIterator();
            while(nite.hasNext()) {
                MethodCallNode mc = (MethodCallNode) nite.next();
                er.addLine(mc.getLine());
            }
            m.setLocation(er);
        }

        if(mocname != null) {
            Message m = _newMessage(cinfo.getName(), Message.stringToMoC(mocname),
                Message.INFORMATION, Message.GETDIRECTOR,
                "Actor " + cinfo.getName() + " has a getDirectory() " +
                "with cast to " + mocname);
            ClassMessageLocation er = new ClassMessageLocation(
                MessageLocation.CLASS_SOURCE);
            er.setClassInfo(cinfo);
            for(int i = 0;i < nodes.size();i++) {
                MethodCallNode mc = (MethodCallNode) nodes.get(i);
                er.addLine(mc.getLine());
            }
            m.setLocation(er);
        }

        return mocname;
    }

    private void _distinctMoCMessage(ClassInfo cinfo, MethodCallNode mc,
            MethodCallNode previous) { 
        Message m = _newMessage(cinfo.getName(), Message.NOMOC,
                    Message.ERROR,
                    Message.DISTINCT_GETDIRECTOR,
                    new String("Multiple getDirector() methods" +
                    " with distinct return types. An actor can " +
                    "only be associated with one director at " +
                    "a time. Ending analysis of " + 
                    cinfo.getName()));
        ClassMessageLocation er = new ClassMessageLocation(
            MessageLocation.CLASS_SOURCE);
        er.setClassInfo(cinfo);
        er.addLine(mc.getLine());
        er.addLine(previous.getLine());
        m.setLocation(er);
    }

    private Message _newMessage(String name, int moc, int status, int code, String text) {
        PreprocessMessage pm = new PreprocessMessage(name, moc, status, 
            code, text);
        _result.addMessage(pm);

        return pm;
    }

    ///////////////////////////////////////////////////////////////////
    ////                         private variables                 ////

    // Informacoes resultantes do preprocessamento.
    private ResultMessages _result;
}
